//
//  CoolView.m
//  testprint
//
//  Created by kienpt on 7/12/14.
//  Copyright (c) 2014 Phan Trung Kien. All rights reserved.
//

#import "CoolView.h"
#include "common.h"
const int MaxStripPixels = 1024*1024;
@implementation CoolView

-(id)initWithDocRef:(NSRect)frame doc:(DocRef *)adocRef
{
    self = [super initWithFrame:frame];
    if (self) {
        docRef = [adocRef retain];
    }
    return self;
}

-(void) dealloc
{
	[docRef release];
	[super dealloc];
}

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
    }
    return self;
}

- (BOOL)knowsPageRange:(NSRangePointer)aRange;
{
    __block NSInteger npages = 0;
	dispatch_sync(queue, ^{
		fz_try(ctx)
		{
			npages = fz_count_pages(docRef->doc);
		}
		fz_catch(ctx);
	});
    *aRange = NSMakeRange(1, npages);
    return YES;
}

- (void)beginPageInRect:(NSRect)aRect atPlacement:(NSPoint)location;
{
     NSLog(@"%ld",(long)[[NSPrintOperation currentOperation] currentPage]);
    _pageNumber = (int)[[NSPrintOperation currentOperation] currentPage];
    [super beginPageInRect:aRect atPlacement:location];
}

- (NSRect)rectForPage:(NSInteger)page;
{
    NSRect bounds = [self bounds];
    return bounds;
}

-(BOOL)acceptsFirstResponder
{
    return YES;
}


static fz_page *getPage(fz_document *doc, int pageIndex)
{
	__block fz_page *page = NULL;
    
	dispatch_sync(queue, ^{
		fz_try(ctx)
		{
			page = fz_load_page(doc, pageIndex);
		}
		fz_catch(ctx)
		{
			printf("Failed to load page\n");
		}
	});
    
	return page;
}

static CGSize getPageSize(fz_document *doc, fz_page *page)
{
	__block CGSize size = {0.0,0.0};
    
	dispatch_sync(queue, ^{
		fz_try(ctx)
		{
			fz_rect bounds;
			fz_bound_page(doc, page, &bounds);
			size.width = bounds.x1 - bounds.x0;
			size.height = bounds.y1 - bounds.y0;
		}
		fz_catch(ctx)
		{
			printf("Failed to find page bounds\n");
		}
	});
    
	return size;
}

static fz_pixmap *createPixMap(CGSize size)
{
	__block fz_pixmap *pix = NULL;
    
	dispatch_sync(queue, ^{
		fz_try(ctx)
		{
			pix = fz_new_pixmap(ctx, fz_device_rgb(ctx), size.width, size.height);
		}
		fz_catch(ctx)
		{
			printf("Failed to create pixmap\n");
		}
	});
    
	return pix;
}

static void freePage(fz_document *doc, fz_page *page)
{
	dispatch_sync(queue, ^{
		fz_free_page(doc, page);
	});
}

static void renderPage(fz_document *doc, fz_page *page, fz_pixmap *pix, fz_matrix *ctm)
{
	dispatch_sync(queue, ^{
		fz_device *dev = NULL;
		fz_var(dev);
		fz_try(ctx)
		{
			dev = fz_new_draw_device(ctx, pix);
			fz_clear_pixmap_with_value(ctx, pix, 0xFF);
			fz_run_page(doc, page, dev, ctm, NULL);
		}
		fz_always(ctx)
		{
			fz_free_device(dev);
		}
		fz_catch(ctx)
		{
			printf("Failed to render page\n");
		}
	});
}

- (void)drawRect:(NSRect)dirtyRect
{
    NSGraphicsContext *context = [NSGraphicsContext currentContext];
    if (![context isDrawingToScreen]) {
        fz_page *page = NULL;
        fz_pixmap *pix = NULL;
        CGDataProviderRef dataref = NULL;
        CGImageRef img = NULL;
        float dpi = 300.0;
        float ppi = 72.0;
        
        if (!context) return;
        
        CGSize paperSize = self.bounds.size;
        page = getPage(docRef->doc, _pageNumber - 1);
        if (page == NULL) return;
        
        CGSize pageSize = getPageSize(docRef->doc, page);
        if (pageSize.width == 0.0 || pageSize.height == 0.0)
            goto exit;
        
        CGSize scale = fitPageToScreen(pageSize, paperSize);
        pageSize.width *= scale.width;
        pageSize.height *= scale.height;
        
        CGSize pageSizePix = {roundf(pageSize.width * dpi / ppi), roundf(pageSize.height * dpi /ppi)};
        int max_strip_height = MaxStripPixels / (int)pageSizePix.width;
        if (pageSizePix.height > max_strip_height)
            pageSizePix.height = max_strip_height;
        CGSize stripSize = {pageSize.width, pageSizePix.height * ppi / dpi};
        
        float cursor = 0.0;
        
        while (cursor < pageSize.height)
        {
            // Overlap strips by 1 point
            if (cursor > 0.0)
                cursor -= 1.0;
            pix = createPixMap(pageSizePix);
            if (!pix)
                goto exit;
            dataref = wrapPixmap(pix);
            if (dataref == NULL)
                goto exit;
            
            img = newCGImageWithPixmap(pix, dataref);
            if (img == NULL)
                goto exit;
            fz_matrix ctm;
            fz_scale(&ctm, dpi / ppi, -dpi / ppi);
            fz_pre_translate(&ctm, 0, -stripSize.height-cursor);
            fz_pre_scale(&ctm, scale.width, scale.height);
            renderPage(docRef->doc, page, pix, &ctm);
            
            CGRect rect = {{0.0,cursor},stripSize};
            NSImage *image = [[NSImage alloc] initWithCGImage:img size:NSMakeSize(rect.size.width,  stripSize.height)];
            NSRect _rectPos = NSMakeRect((paperSize.width - rect.size.width)/2,cursor, rect.size.width , rect.size.height);
            NSRect imageRect = NSMakeRect(0,0, rect.size.width , rect.size.height);
            [image drawInRect:_rectPos fromRect:imageRect operation:NSCompositeSourceOver fraction:1.0];
            [image release];
            image = nil;
            CGImageRelease(img);
            img = NULL;
            CGDataProviderRelease(dataref); // releases pix
            dataref = NULL;
            cursor += stripSize.height;
        }
        exit:
        freePage(docRef->doc, page);
        CGImageRelease(img);
        CGDataProviderRelease(dataref); //releases pix
        [self setNeedsDisplay:YES];
    }
    [super drawRect:dirtyRect];
}

- (BOOL)isFlipped
{
    return YES;
}

@end
